using GrapeCity.Forguncy.Commands;
using GrapeCity.Forguncy.Log;
using GrapeCity.Forguncy.Plugin;
using LiteVectorIndex.Engine;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text.Json;
using System.Threading.Tasks;

namespace LiteVectorIndex
{
    [Icon("pack://application:,,,/LiteVectorIndex;component/Resources/Icon.png")]
    [Category("嵌入式向量库")]
    [OrderWeight(990)]
    public class Cluster_ConvertFromFaiss : Command, ICommandExecutableInServerSideAsync
    {
        [FormulaProperty]
        [DisplayName("集合名")]
        [Description("如果之前加载过同名的集合，本操作将会先将既有集合删除，然后重建。")]
        public object KBName { get; set; }

        [ComboProperty]
        [DisplayName("距离算法")]
        [Description("需根据应用场景采用不同的距离算法。如Cosine适用于语义检索，IP适用于特征值推荐，L2用于度量学习等。")]
        public MetricType MetricTypeInUse { get; set; } = MetricType.Cosine;


        [FormulaProperty]
        [DisplayName("JSON（来自Faiss插件）")]
        [Description("JSON格式的字符串，反序列化可得到一个对象，属性名为文本ID，属性值是向量（float数组）")]
        public object JSONExp { get; set; }

        [DisplayName("将处理结果保存到变量")]
        [Description("Gzip压缩后的文本，包含集合的全部数据。")]
        [ResultToProperty]
        public string ResultInParamater { get; set; }

        public async Task<ExecuteResult> ExecuteAsync(IServerCommandExecuteContext dataContext)
        {
            var name = (await dataContext.EvaluateFormulaAsync(KBName))?.ToString() ?? "";
            var objectJSON = (await dataContext.EvaluateFormulaAsync(JSONExp))?.ToString() ?? "";

            // 先删除已经存在的集合
            if (CollectionManager.Instance.CollectionExists(name))
            {
                dataContext.Log.AppendLine($"向量集合：{name} 已经被加载到内存，先执行移除操作。");
                CollectionManager.Instance.RemoveCollection(name);
            }

            // 创建新的集合
            var collection = CollectionManager.Instance.CreateNewCollection(name, MetricTypeInUse, true);
            dataContext.Log.AppendLine($"向量集合：{name} 创建成功，维度：{collection.Dimension}，类型：{collection.MetricTypeInUse}，同一化：{collection.NormalizeOnAddAndQuery}。");


            loadFromFaissPlugin(collection, objectJSON);

            dataContext.Log.AppendLine($"向量集合：{name} 从Faiss插件的JSON数据加载成功，共 {collection.Count} 条数据，维度：{collection.Dimension}，类型：{collection.MetricTypeInUse}，同一化：{collection.NormalizeOnAddAndQuery}。");

            if (ResultInParamater != null)
            {
                // 将集合数据序列化为BASE64字符串
                dataContext.Parameters[ResultInParamater] = FastSerializer.ToZipBase64(collection.GetData());
            }

            return new ExecuteResult();
        }

        public override string ToString()
        {
            return "嵌入式向量库：从Faiss插件转换";
        }

        public override CommandScope GetCommandScope()
        {
            return CommandScope.ExecutableInServer;
        }

        /// <summary>
        /// 从JSON字符串加载Cluster数据。
        /// </summary>
        /// <param name="objectJSON">JSON字符串。属性名为ID，属性值为向量数组</param>
        /// <exception cref="InvalidOperationException">当JSON格式错误时抛出异常。</exception>
        private void loadFromFaissPlugin(LiteVectorCollection collection
            , string objectJSON)
        {
            // 忽略空字符串输入，用来应对初始化场景
            if (!string.IsNullOrEmpty(objectJSON))
            {
                var data = JsonSerializer.Deserialize<Dictionary<int, float[]>>(objectJSON);

                if (data == null)
                    throw new InvalidOperationException("加载矢量集合出错，传入参数不是 Dictionary<int, float[]> 类型。");

                // 添加数据
                List<(int id, float[] vector)> toAdd = new List<(int id, float[] vector)>();

                foreach (var kv in data)
                {
                    toAdd.Add((kv.Key, kv.Value));
                }

                collection.AddVectors(toAdd); // 批量添加数据

            }
        }


    }
}
